// An OpenGL display of a ship's cockpit.

#ifndef COCKPIT_H_
#define COCKPIT_H_

#ifdef __APPLE_CC__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include "ship.h"
#include "landscape.h"
#include <cmath>

const double PI = acos(-1);

class Cockpit {
  Ship* ship;
  Landscape* landscape;
  int cockpitId;
  double radarSizeMod;
public:
  Cockpit(Ship* ship, Landscape* landscape): ship(ship), landscape(landscape) {}
  void create();
  void draw();
  void drawInstruments();
  void updateLandscape(Landscape* newLandscape);
};

void Cockpit::create() {
  cockpitId = glGenLists(1);
  glNewList(cockpitId, GL_COMPILE);
  glDisable(GL_LIGHTING);

  // Create the panel
  glColor3f(0.8, 0.8, 0.7);
  glBegin(GL_TRIANGLE_FAN);
  glVertex3f(0, -1, 0);
  glVertex3f(1, -1, 0);
  for (double x = 1.0; x >= -1.05; x -= 0.05) {
    glVertex3f(x, 20*cos(x / 10.0) - 20.6, 0);
  }
  glVertex3f(-1, -1, 0);
  glEnd();

  // Create the spedometer rectangle
  glColor3f(0.25, 0.25, 0.25);
  glBegin(GL_QUADS);
    glVertex3f(-1.1, -1.1, -0.2);
    glVertex3f(-1.1, -0.92, -0.2);
    glVertex3f(1.1, -0.92, -0.2);
    glVertex3f(1.1, -1.1, -0.2);
  glEnd();

  // Create the altimeter rectangle
  glBegin(GL_QUADS);
    glVertex3f(-0.3, -0.9, -0.2);
    glVertex3f(-0.3, -0.65, -0.2);
    glVertex3f(-0.5, -0.65, -0.2);
    glVertex3f(-0.5, -0.9, -0.2);
  glEnd();

  // Create the tilt indicator rectangle
  glBegin(GL_QUADS);
    glVertex3f(0.3, -0.9, -0.2);
    glVertex3f(0.3, -0.65, -0.2);
    glVertex3f(0.5, -0.65, -0.2);
    glVertex3f(0.5, -0.9, -0.2);
  glEnd();

  // Create the tilt indicator triangles
  glBegin(GL_TRIANGLES);
    glVertex3f(0.52, -0.75, -0.2);
    glVertex3f(0.57, -0.65, -0.2);
    glVertex3f(0.62, -0.75, -0.2);

    glVertex3f(0.52, -0.8, -0.2);
    glVertex3f(0.57, -0.9, -0.2);
    glVertex3f(0.62, -0.8, -0.2);
  glEnd();

  // Finally, make the minimap rectangle
  glBegin(GL_QUADS);
    glVertex3f(-0.2, -0.9, -0.2);
    glVertex3f(-0.2, -0.65, -0.2);
    glVertex3f(0.2, -0.65, -0.2);
    glVertex3f(0.2, -0.9, -0.2);
  glEnd();

  glEnable(GL_LIGHTING);

  glEndList();
}

inline void Cockpit::draw() {
  glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
  glLoadIdentity();
  glPushAttrib(GL_CURRENT_BIT);
  glMatrixMode(GL_PROJECTION);
  glPushMatrix();
  glLoadIdentity();
  glCallList(cockpitId);
  drawInstruments();
  glPopAttrib();
  glPopMatrix();
  glMatrixMode(GL_MODELVIEW);
  glPopMatrix();
}

// Update the landscape on user-refreshes
inline void Cockpit::updateLandscape(Landscape* newLandscape) {
  landscape = newLandscape;
}

// Draws the instrument panel interactive elements
inline void Cockpit::drawInstruments() {
  // Begin with the spedometer, filling in the bottom
  // bar with a green -> red (max speed) indicator
  glDisable(GL_LIGHTING);
  double speedPercent = ship->getSpeed() / ship->getMaxSpeed();
  glColor3f((speedPercent > 0) ? speedPercent : -speedPercent,
            (speedPercent > 0) ? 1 - speedPercent : 0,
            (speedPercent > 0) ? 0 : 1);
  glBegin(GL_QUADS);
    glVertex3f(-1.1, -1.1, -0.3);
    glVertex3f(-1.1, -0.92, -0.3);
    glVertex3f(-1 + fabs(2 * speedPercent), -0.92, -0.3);
    glVertex3f(-1 + fabs(2 * speedPercent), -1.1, -0.3);
  glEnd();

  // Next, we work on the altimeter
  Point shipPos = ship->getPosition();
  double landscapeHeight = landscape->getHeightAt(shipPos.x, shipPos.y, shipPos.z),
         MAX_HEIGHT = ship->getMaxHeight(),
         shipRatio,
         groundRatio;
  // Make sure the ship is still on the map
  if (landscapeHeight != -1) {
    groundRatio = landscapeHeight / MAX_HEIGHT;
  } else {
    groundRatio = 0;
  }
  shipRatio = (shipPos.y > 0) ? shipPos.y / MAX_HEIGHT : 0;

  // Draw the ship's position relative to the ground height
  glColor3f(0.0, 0.0, 1.0);
  glBegin(GL_QUADS);
    glVertex3f(-0.3, -0.9, -0.21);
    glVertex3f(-0.3, -0.9 + (0.25 * shipRatio), -0.21);
    glVertex3f(-0.5, -0.9 + (0.25 * shipRatio), -0.21);
    glVertex3f(-0.5, -0.9, -0.21);
  glEnd();

  // Draw the ground height indicator
  glColor3f(0.0, 1.0, 0.0);
  glBegin(GL_QUADS);
    glVertex3f(-0.3, -0.9, -0.22);
    glVertex3f(-0.3, -0.9 + (0.25 * groundRatio), -0.22);
    glVertex3f(-0.5, -0.9 + (0.25 * groundRatio), -0.22);
    glVertex3f(-0.5, -0.9, -0.22);
  glEnd();

  // Good! That's done... let's do the tilt indicator
  // Start with the triangles because they're easy
  glColor3f(0.25, 0.25 + 0.5 * ship->getPitch(), 0.25);
  if (ship->getForward().j > 0) {
    glBegin(GL_TRIANGLES);
      glVertex3f(0.52, -0.75, -0.21);
      glVertex3f(0.57, -0.65, -0.21);
      glVertex3f(0.62, -0.75, -0.21);
    glEnd();
  } else {
    glBegin(GL_TRIANGLES);
      glVertex3f(0.52, -0.8, -0.21);
      glVertex3f(0.57, -0.9, -0.21);
      glVertex3f(0.62, -0.8, -0.21);
    glEnd();
  }

  // Now draw the ship roll indicator
  glColor3f(0.0, 0.0, 1.0);
  double angle = (ship->getRight().j >= 0) ? ship->getRoll() : -ship->getRoll();
  glBegin(GL_LINES);
    glVertex3f(0.4 + 0.08 * cos(angle), -0.775 + 0.08 * sin(angle), -0.21);
    glVertex3f(0.4 + 0.08 * cos(angle + PI), -0.775 + 0.08 * sin(angle + PI), -0.21);
  glEnd();

  // Finally, draw the topside indicator
  glBegin(GL_TRIANGLES);
    glVertex3f(0.4 + 0.03 * cos(angle), -0.775 + 0.03 * sin(angle), -0.21);
    glVertex3f(0.4 + 0.03 * cos(angle + PI), -0.775 + 0.03 * sin(angle + PI), -0.21);
    glVertex3f(0.4 + 0.03 * cos(angle + PI / 2), -0.775 + 0.03 * sin(angle + PI / 2), -0.21);
  glEnd();

  // OK... so... we're going to draw the minimap now
  // Start with a representation of the land square in the center
  double resizeLandscapeX = 1,
         resizeLandscapeZ = 1,
         landscapeRows = landscape->getRows(),
         landscapeColumns = landscape->getColumns();
  if (landscapeRows > landscapeColumns) {
    resizeLandscapeZ = (double) landscapeColumns / landscapeRows;
  } else {
    resizeLandscapeX = (double) landscapeRows / landscapeColumns;
  }

  // Set the size mod to its appropriate value
  if (!radarSizeMod) {
    radarSizeMod = 1.0;
  }

  if ((shipPos.x > landscapeRows * radarSizeMod || (shipPos.x < -landscapeRows * (radarSizeMod - 1)))
      || (shipPos.z > landscapeColumns * radarSizeMod || (shipPos.z < -landscapeColumns * (radarSizeMod - 1)))) {
    radarSizeMod++;
  } else if((shipPos.x < landscapeRows * (radarSizeMod - 1) && (shipPos.x > -landscapeRows * (radarSizeMod - 2)))
      && ((shipPos.z < landscapeColumns * (radarSizeMod - 1)) && (shipPos.z > -landscapeColumns * (radarSizeMod - 2)))) {
    radarSizeMod--;
  }

  // Draws a green square representing the land mass
  glColor3f(0.0, 1.0, 0.0);
  glBegin(GL_QUADS);
    glVertex3f(-0.125 * resizeLandscapeX / radarSizeMod,
               -0.775 + 0.125 * resizeLandscapeZ / radarSizeMod,
               -0.21);
    glVertex3f(-0.125 * resizeLandscapeX / radarSizeMod,
               -0.775 - 0.125 * resizeLandscapeZ / radarSizeMod,
               -0.21);
    glVertex3f(0.125 * resizeLandscapeX / radarSizeMod,
               -0.775 - 0.125 * resizeLandscapeZ / radarSizeMod,
               -0.21);
    glVertex3f(0.125 * resizeLandscapeX / radarSizeMod,
               -0.775 + 0.125 * resizeLandscapeZ / radarSizeMod,
               -0.21);
  glEnd();

  // Now draw the ship representation
  double shipXScaled = ((shipPos.x - landscapeRows / 2)) / (landscapeRows * radarSizeMod),
         shipZScaled = ((shipPos.z  - landscapeColumns / 2)) / (landscapeColumns * radarSizeMod);
  glColor3f(0.0, 0.0, 1.0);
  glBegin(GL_QUADS);
    glVertex3f(-0.008 + shipXScaled * 0.125, -0.767 + shipZScaled * 0.125, -0.22);
    glVertex3f(-0.008 + shipXScaled * 0.125, -0.783 + shipZScaled * 0.125, -0.22);
    glVertex3f(0.008 + shipXScaled * 0.125, -0.783 + shipZScaled * 0.125, -0.22);
    glVertex3f(0.008 + shipXScaled * 0.125, -0.767 + shipZScaled * 0.125, -0.22);
  glEnd();

  glEnable(GL_LIGHTING);
}

#endif
